"""
Markdown file parser using markdown library
"""
import time
import re
from pathlib import Path
from typing import Union, List, Dict, Any
import logging

try:
    import markdown
    from markdown.extensions import toc, tables, codehilite
except ImportError:
    markdown = None

from .base import FileParser, ParseResult, FileType

logger = logging.getLogger(__name__)


class MarkdownParser(FileParser):
    """
    Parser for Markdown files using markdown library
    """
    
    def __init__(self, max_file_size: int = 10 * 1024 * 1024):
        super().__init__(max_file_size)
        
        if markdown is None:
            raise ImportError("markdown is required for Markdown parsing. Install with: pip install markdown")
    
    def supports_file_type(self, file_type: FileType) -> bool:
        """Check if parser supports Markdown files"""
        return file_type == FileType.MARKDOWN
    
    def parse(self, file_path: Union[str, Path]) -> ParseResult:
        """
        Parse Markdown file and extract text content
        
        Args:
            file_path: Path to the Markdown file
            
        Returns:
            ParseResult with extracted text and metadata
        """
        start_time = time.time()
        file_path = Path(file_path)
        
        # Validate file
        if not self.validate_file(file_path):
            return self.create_error_result("File validation failed", file_path)
        
        try:
            # Read file content
            with open(file_path, 'r', encoding='utf-8') as file:
                raw_content = file.read()
            
            if not raw_content.strip():
                return self.create_error_result("Empty Markdown file", file_path)
            
            # Initialize metadata
            metadata = {}
            
            # Parse frontmatter if present
            frontmatter_data, content_without_frontmatter = self._extract_frontmatter(raw_content)
            if frontmatter_data:
                metadata.update(frontmatter_data)
            
            # Create markdown parser with extensions
            md = markdown.Markdown(
                extensions=[
                    'toc',
                    'tables', 
                    'codehilite',
                    'fenced_code',
                    'def_list',
                    'footnotes',
                    'attr_list'
                ],
                extension_configs={
                    'toc': {
                        'title': 'Table of Contents'
                    }
                }
            )
            
            # Convert to HTML first, then extract plain text
            html_content = md.convert(content_without_frontmatter)
            
            # Extract plain text from HTML
            plain_text = self._html_to_text(html_content)
            
            # Analyze markdown structure
            structure_info = self._analyze_structure(content_without_frontmatter)
            metadata.update(structure_info)
            
            # Get table of contents if available
            if hasattr(md, 'toc') and md.toc:
                metadata['table_of_contents'] = md.toc
            
            # Add markdown-specific metadata
            metadata.update({
                'has_frontmatter': len(frontmatter_data) > 0,
                'character_count': len(content_without_frontmatter),
                'line_count': len(content_without_frontmatter.split('\n')),
            })
            
            processing_time = time.time() - start_time
            
            return self.create_success_result(
                content=plain_text,
                file_path=file_path,
                file_type=FileType.MARKDOWN,
                processing_time=processing_time,
                additional_metadata=metadata
            )
            
        except UnicodeDecodeError as e:
            error_msg = f"Unicode decode error: {str(e)}"
            logger.error(error_msg)
            return self.create_error_result(error_msg, file_path)
        
        except Exception as e:
            error_msg = f"Error parsing Markdown file: {str(e)}"
            logger.error(error_msg)
            return self.create_error_result(error_msg, file_path)
    
    def _extract_frontmatter(self, content: str) -> tuple[Dict[str, Any], str]:
        """
        Extract YAML frontmatter from markdown content
        
        Args:
            content: Raw markdown content
            
        Returns:
            Tuple of (frontmatter_dict, content_without_frontmatter)
        """
        frontmatter_pattern = r'^---\s*\n(.*?)\n---\s*\n'
        match = re.match(frontmatter_pattern, content, re.DOTALL)
        
        if not match:
            return {}, content
        
        frontmatter_raw = match.group(1)
        content_without_frontmatter = content[match.end():]
        
        # Simple YAML parsing (basic key-value pairs)
        frontmatter = {}
        for line in frontmatter_raw.split('\n'):
            line = line.strip()
            if ':' in line:
                key, value = line.split(':', 1)
                key = key.strip()
                value = value.strip().strip('"\'')
                frontmatter[key] = value
        
        return frontmatter, content_without_frontmatter
    
    def _html_to_text(self, html_content: str) -> str:
        """
        Convert HTML content to plain text
        
        Args:
            html_content: HTML string
            
        Returns:
            Plain text string
        """
        # Remove HTML tags using regex (simple approach)
        # For better HTML parsing, could use BeautifulSoup
        
        # Replace common HTML entities
        html_content = html_content.replace('&lt;', '<')
        html_content = html_content.replace('&gt;', '>')
        html_content = html_content.replace('&amp;', '&')
        html_content = html_content.replace('&quot;', '"')
        html_content = html_content.replace('&#39;', "'")
        
        # Convert HTML structures to text equivalents
        html_content = re.sub(r'<h[1-6][^>]*>', '\n\n# ', html_content)  # Headers
        html_content = re.sub(r'</h[1-6]>', '\n\n', html_content)
        html_content = re.sub(r'<p[^>]*>', '\n\n', html_content)  # Paragraphs
        html_content = re.sub(r'</p>', '\n\n', html_content)
        html_content = re.sub(r'<br[^>]*>', '\n', html_content)  # Line breaks
        html_content = re.sub(r'<li[^>]*>', '\n• ', html_content)  # List items
        html_content = re.sub(r'</li>', '', html_content)
        html_content = re.sub(r'<tr[^>]*>', '\n', html_content)  # Table rows
        html_content = re.sub(r'<td[^>]*>|<th[^>]*>', ' | ', html_content)  # Table cells
        
        # Remove all remaining HTML tags
        html_content = re.sub(r'<[^>]+>', '', html_content)
        
        # Clean up whitespace
        lines = []
        for line in html_content.split('\n'):
            line = line.strip()
            if line:
                lines.append(line)
        
        return '\n'.join(lines)
    
    def _analyze_structure(self, content: str) -> Dict[str, Any]:
        """
        Analyze markdown structure and extract metadata
        
        Args:
            content: Markdown content
            
        Returns:
            Dictionary with structure information
        """
        structure = {
            'headers': [],
            'code_blocks': [],
            'links': [],
            'images': [],
            'tables': 0,
            'lists': 0,
        }
        
        lines = content.split('\n')
        
        for line_num, line in enumerate(lines, 1):
            line = line.strip()
            
            # Headers
            if line.startswith('#'):
                level = 0
                for char in line:
                    if char == '#':
                        level += 1
                    else:
                        break
                header_text = line[level:].strip()
                structure['headers'].append({
                    'level': level,
                    'text': header_text,
                    'line': line_num
                })
            
            # Code blocks
            if line.startswith('```'):
                language = line[3:].strip()
                structure['code_blocks'].append({
                    'language': language,
                    'line': line_num
                })
            
            # Links
            link_pattern = r'\[([^\]]+)\]\(([^)]+)\)'
            links = re.findall(link_pattern, line)
            for link_text, link_url in links:
                structure['links'].append({
                    'text': link_text,
                    'url': link_url,
                    'line': line_num
                })
            
            # Images
            image_pattern = r'!\[([^\]]*)\]\(([^)]+)\)'
            images = re.findall(image_pattern, line)
            for img_alt, img_src in images:
                structure['images'].append({
                    'alt': img_alt,
                    'src': img_src,
                    'line': line_num
                })
            
            # Tables (simple detection)
            if '|' in line and line.strip().startswith('|'):
                structure['tables'] += 1
            
            # Lists (simple detection)
            if re.match(r'^[\s]*[\*\-\+]\s', line) or re.match(r'^[\s]*\d+\.\s', line):
                structure['lists'] += 1
        
        # Add counts
        structure.update({
            'header_count': len(structure['headers']),
            'code_block_count': len(structure['code_blocks']),
            'link_count': len(structure['links']),
            'image_count': len(structure['images']),
        })
        
        return structure
    
    def extract_headers_only(self, file_path: Union[str, Path]) -> List[Dict[str, Any]]:
        """
        Extract only headers from markdown file
        
        Args:
            file_path: Path to the Markdown file
            
        Returns:
            List of header dictionaries with level, text, and line number
        """
        file_path = Path(file_path)
        
        if not self.validate_file(file_path):
            return []
        
        try:
            with open(file_path, 'r', encoding='utf-8') as file:
                content = file.read()
            
            headers = []
            lines = content.split('\n')
            
            for line_num, line in enumerate(lines, 1):
                line = line.strip()
                if line.startswith('#'):
                    level = 0
                    for char in line:
                        if char == '#':
                            level += 1
                        else:
                            break
                    header_text = line[level:].strip()
                    headers.append({
                        'level': level,
                        'text': header_text,
                        'line': line_num
                    })
            
            return headers
            
        except Exception as e:
            logger.error(f"Error extracting headers: {e}")
            return []
    
    def get_markdown_info(self, file_path: Union[str, Path]) -> dict:
        """
        Get Markdown file metadata without full parsing
        
        Args:
            file_path: Path to the Markdown file
            
        Returns:
            Dictionary with file metadata
        """
        file_path = Path(file_path)
        
        try:
            with open(file_path, 'r', encoding='utf-8') as file:
                content = file.read()
            
            # Basic statistics
            lines = content.split('\n')
            info = {
                'line_count': len(lines),
                'character_count': len(content),
                'word_count': len(content.split()),
            }
            
            # Extract frontmatter
            frontmatter, _ = self._extract_frontmatter(content)
            info['has_frontmatter'] = len(frontmatter) > 0
            info['frontmatter'] = frontmatter
            
            # Quick structure analysis
            structure = self._analyze_structure(content)
            info.update({
                'header_count': structure['header_count'],
                'code_block_count': structure['code_block_count'],
                'link_count': structure['link_count'],
                'image_count': structure['image_count'],
                'table_count': structure['tables'],
                'list_count': structure['lists'],
            })
            
            return info
            
        except Exception as e:
            logger.error(f"Error getting markdown info: {e}")
            return {"error": str(e)}